package com.smart.manager.task;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.smart.common.annotation.TaskBean;
import com.smart.common.annotation.TaskMethod;
import com.smart.common.cache.CacheService;
import com.smart.common.entities.domain.TaskResult;
import com.smart.manager.product.entities.assembler.ReqCamera;
import com.smart.manager.product.entities.enums.CameraPlace;
import com.smart.manager.product.entities.enums.CameraStatus;
import com.smart.manager.product.entities.models.BasicCamera;
import com.smart.manager.product.entities.models.query.QBasicCamera;
import com.smart.manager.system.repository.ConfigRepository;
import io.ebean.DB;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 获取摄像头
 *
 * @author leo
 * @date 2023/09/011
 */
@Log4j2
@Component
@TaskBean
@RequiredArgsConstructor
public class CameraTask {

    private final CacheService cacheService;
    private final ConfigRepository configRepository;

    /**
     * 同步摄像头地址
     */
    private final static  String synchronous = "https://open.ys7.com/api/lapp/device/list";

    /**
     * 同步萤石云摄像头
     *
     * @return {@link TaskResult}
     */
    @TaskMethod(title = "同步萤石云摄像头")
    public synchronized TaskResult earTagData() {
        log.warn("准备 同步萤石云摄像头！");
        //开始更新token
        cacheService.getCameraTokenCache().put("accessToken",upToken());

        String token = cacheService.getCameraTokenCache().get("accessToken");
        List<ReqCamera.CameraList> di = di(new ArrayList<>(), 0,token);
        try {
            if (CollUtil.isNotEmpty(di)) {
                List<BasicCamera> rfid = new QBasicCamera().findList();
                List<ReqCamera.CameraList> rfidEars = JSONUtil.parseArray(JSONUtil.toJsonStr(rfid)).toList(ReqCamera.CameraList.class);
                String date = upToDate(di, rfidEars, rfid);
                log.warn(di);
                return new TaskResult(true, date);
            }
        } catch (Exception e) {
            return new TaskResult(false , "更新失败:"+e.getMessage());
        }
        return new TaskResult(false, "更新失败");
    }

    /**
     *  递归请求数据
     * @return {@link List}<{@link ReqCamera.CameraList}>
     */
    public List<ReqCamera.CameraList> di(List<ReqCamera.CameraList> cameraList, int pageStart,String token) {
        if (StrUtil.isBlank(token)){
            token = upToken();
            cacheService.getCameraTokenCache().put("accessToken",token);
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("accessToken", token);
        map.put("pageStart", pageStart);
        map.put("pageSize", 10);  //API 每次请求做多分页10条
        HttpResponse execute = HttpRequest.post(synchronous).form(map).execute();
        JSONObject object = new JSONObject(execute.body());
        if (!object.get("code").equals("200")) {
            //结束 请求异常
            return null;
        }
        JSONObject page = new JSONObject(object.get("page"));
        Object data = object.get("data");
        List<ReqCamera.CameraList> cameras = JSONUtil.parseArray(data).toList(ReqCamera.CameraList.class);
        cameraList.addAll(cameras);
        if (!Objects.requireNonNull(page).getInt("total").equals(0)) {
            if (!(cameraList.size() == page.getInt("total"))) {
                di(cameraList, ++pageStart,token);
            }
        }
        return cameraList;
    }

    /**
     * 更新token
     * @return {@link String}
     */
    public String upToken(){
        com.alibaba.fastjson2.JSONObject camera = configRepository.readCache("Camera");
        HashMap<String, Object> map = new HashMap<>();
        map.put("appKey", camera.get("appKey"));
        map.put("appSecret", camera.get("appSecret"));
        HttpResponse execute = HttpRequest.post("https://open.ys7.com/api/lapp/token/get").form(map).execute();
        JSONObject object = new JSONObject(execute.body());
        if (!Objects.equals(object.get("code"),"200")){
            throw new RuntimeException(ObjectUtil.isNotEmpty(object.get("msg"))?(String) object.get("msg"):"请求token接口异常");
        }
        Object data = object.get("data");
        Object token = new JSONObject(data).get("accessToken");
        return (String) token;
    }


    /**
     * 更新数据
     * @param newly
     * @param old
     * @param original
     * @return {@link String}
     * @throws Exception
     */
    public String upToDate(List<ReqCamera.CameraList> newly, List<ReqCamera.CameraList> old, List<BasicCamera> original) throws Exception {
        List<BasicCamera> update = new ArrayList<>();
        List<BasicCamera> add = new ArrayList<>();
        List<BasicCamera> del = new ArrayList<>();
        Set<String> cNewly = newly.stream().map(ReqCamera.CameraList::getDeviceSerial).collect(Collectors.toSet());
        Set<String> cOld = old.stream().map(ReqCamera.CameraList::getDeviceSerial).collect(Collectors.toSet());
        //离线的数据
        old.stream().filter(x -> CollUtil.subtract(cOld, cNewly).contains(x.getDeviceSerial())).collect(Collectors.toList()).forEach(x -> old.forEach(c -> {
            if (!c.equals(x)) {
                for (BasicCamera v : original) {
                    if (v.getDeviceSerial().equals(c.getDeviceSerial())) {
                        BeanUtil.copyProperties(c, v);
                        del.add(v);
                    }
                }
            }
        }));
        //新增的数据
        newly.stream().filter(x -> CollUtil.subtract(cNewly, cOld).contains(x.getDeviceSerial())).collect(Collectors.toList()).forEach(rfid -> {
            Opt.ofBlankAble(BeanUtil.copyProperties(rfid, BasicCamera.class)).ifPresent(c -> {
                c.setCameraStatus(CameraStatus.NOT_BOUND);
                c.setPlace(CameraPlace.DISTRIBUTION);
                c.setAddTime(LocalDateTimeUtil.of(rfid.getAddTime()));
                add.add(c);
            });
        });
        //修改数据
        List<ReqCamera.CameraList> updateList = newly.stream().filter(x -> CollUtil.intersectionDistinct(cNewly, cOld).contains(x.getDeviceSerial())).collect(Collectors.toList());
        for (ReqCamera.CameraList x : updateList) {
            ReqCamera.CameraList basic = null;
            for (ReqCamera.CameraList c : old) {
                if (c.getDeviceSerial().equals(x.getDeviceSerial())) {
                    basic = c;
                    break;
                }
            }
            if (basic != null && !ObjectUtil.equals(basic, x)) {
                ReqCamera.CameraList reqRfidEar = updateList.get(old.indexOf(basic));
                for (BasicCamera v : original) {
                    if (v.getDeviceSerial().equals(reqRfidEar.getDeviceSerial())) {
                        BeanUtil.copyProperties(reqRfidEar, v);
                        v.setAddTime(LocalDateTimeUtil.of(reqRfidEar.getAddTime()));
                        update.add(v);
                    }
                }
            }
        }
        log.warn("摄像头数据更新：修改的数据 有 = {} 条", update.size());
        log.warn("摄像头数据更新：新增的数据 有 = {} 条", add.size());
        log.warn("摄像头数据更新：被移出的数据 有 = {} 条", del.size());
        Opt.ofBlankAble(add).ifPresent(DB::insertAll);
        Opt.ofBlankAble(update).ifPresent(DB::updateAll);
//        Opt.ofBlankAble(del).ifPresent(DB::updateAll);
        return "摄像头更新：新增:" + add.size() + "条,更新:" + update.size() + "条,移出:" + del.size() + "条";
    }
}
